/* 测试用户管理子服务的客户端 */
#include <gflags/gflags.h>
#include <brpc/channel.h>
#include <thread>
#include <gtest/gtest.h>
#include "logger.hpp"
#include "brpc.hpp"
#include "etcd.hpp"
#include "base.pb.h"
#include "user.pb.h"
#include "utils.hpp"

DEFINE_bool(run_mode, false, "程序的运行模式，false-调试；true-发布");
DEFINE_string(log_file, "", "发布模式下，用于指定日志的输出文件");
DEFINE_int32(log_level, 0, "发布模式下，用于指定日志输出等级");

DEFINE_string(etcd_host, "127.0.0.1:2379", "服务注册中心地址");
DEFINE_string(base_service, "/service", "服务监控根目录");
DEFINE_string(user_service, "/service/user_service", "调用的服务目录");

ChatSystem::ServiceManager::ptr service_manager;
ChatSystem::UserInfo user_info;
std::string nickanme_login_ssid;
std::string phone_login_ssid;


TEST(用户子服务测试, 用户注册测试) {
    auto channel = service_manager->choose(FLAGS_user_service);
    ASSERT_TRUE(channel);
    user_info.set_nickname("nickname4");

    //发起User Rpc调用
    // 2.实例化pb中的UserService_Stub类对象；
    ChatSystem::UserService_Stub stub(channel.get());
    // 3.发起rpc请求，获取响应进行处理；
    brpc::Controller cntl;
    ChatSystem::UserRegisterReq req;
    ChatSystem::UserRegisterRsp rsp;
    req.set_request_id(ChatSystem::Util::uuid());
    req.set_nickname(user_info.nickname());
    req.set_password("123456");

    stub.UserRegister(&cntl, &req, &rsp, nullptr);
    ASSERT_FALSE(cntl.Failed());
    ASSERT_TRUE(rsp.success());

}

TEST(用户子服务测试, 用户登录测试) 
{
    auto channel = service_manager->choose(FLAGS_user_service);
    ASSERT_TRUE(channel);

    //发起User Rpc调用
    // 2.实例化pb中的UserService_Stub类对象；
    ChatSystem::UserService_Stub stub(channel.get());
    // 3.发起rpc请求，获取响应进行处理；
    brpc::Controller cntl;
    ChatSystem::UserLoginReq req;
    ChatSystem::UserLoginRsp rsp;

    req.set_request_id(ChatSystem::Util::uuid());
    req.set_nickname(user_info.nickname());
    req.set_password("123456");

    stub.UserLogin(&cntl, &req, &rsp, nullptr);
    ASSERT_FALSE(cntl.Failed());
    ASSERT_TRUE(rsp.success());
    nickanme_login_ssid = rsp.login_session_id();

}

TEST(用户子服务测试, 用户头像修改测试) 
{
    auto channel = service_manager->choose(FLAGS_user_service);
    ASSERT_TRUE(channel);

    //发起User Rpc调用
    // 2.实例化pb中的UserService_Stub类对象；
    ChatSystem::UserService_Stub stub(channel.get());
    // 3.发起rpc请求，获取响应进行处理；
    brpc::Controller cntl;
    ChatSystem::SetUserAvatarReq req;
    ChatSystem::SetUserAvatarRsp rsp;

    req.set_request_id(ChatSystem::Util::uuid());
    req.set_user_id(user_info.user_id());
    req.set_login_session_id(nickanme_login_ssid);
    req.set_avatar(user_info.avatar());

    stub.SetUserAvatar(&cntl, &req, &rsp, nullptr);
    ASSERT_FALSE(cntl.Failed());
    ASSERT_TRUE(rsp.success());

}
TEST(用户子服务测试, 用户昵称修改测试) 
{
    auto channel = service_manager->choose(FLAGS_user_service);
    ASSERT_TRUE(channel);

    //发起User Rpc调用
    // 2.实例化pb中的UserService_Stub类对象；
    ChatSystem::UserService_Stub stub(channel.get());
    // 3.发起rpc请求，获取响应进行处理；
    brpc::Controller cntl;
    ChatSystem::SetUserNicknameReq req;
    ChatSystem::SetUserNicknameRsp rsp;

    req.set_request_id(ChatSystem::Util::uuid());
    req.set_user_id(user_info.user_id());
    req.set_login_session_id(nickanme_login_ssid);
    req.set_nickname("测试昵称3");
    


    stub.SetUserNickname(&cntl, &req, &rsp, nullptr);
    ASSERT_FALSE(cntl.Failed());
    ASSERT_TRUE(rsp.success());
    user_info.set_nickname("测试昵称3");
}

TEST(用户子服务测试, 用户签名修改测试) 
{
    auto channel = service_manager->choose(FLAGS_user_service);
    ASSERT_TRUE(channel);

    //发起User Rpc调用
    // 2.实例化pb中的UserService_Stub类对象；
    ChatSystem::UserService_Stub stub(channel.get());
    // 3.发起rpc请求，获取响应进行处理；
    brpc::Controller cntl;
    ChatSystem::SetUserDescriptionReq req;
    ChatSystem::SetUserDescriptionRsp rsp;

    req.set_request_id(ChatSystem::Util::uuid());
    req.set_user_id(user_info.user_id());
    req.set_login_session_id(nickanme_login_ssid);
    req.set_description(user_info.description());

    stub.SetUserDescription(&cntl, &req, &rsp, nullptr);
    ASSERT_FALSE(cntl.Failed());
    ASSERT_TRUE(rsp.success());
}

TEST(用户子服务测试, 用户信息获取测试) 
{
    auto channel = service_manager->choose(FLAGS_user_service);
    ASSERT_TRUE(channel);

    //发起User Rpc调用
    // 2.实例化pb中的UserService_Stub类对象；
    ChatSystem::UserService_Stub stub(channel.get());
    // 3.发起rpc请求，获取响应进行处理；
    brpc::Controller cntl;
    ChatSystem::GetUserInfoReq req;
    ChatSystem::GetUserInfoRsp rsp;

    req.set_request_id(ChatSystem::Util::uuid());
    req.set_user_id(user_info.user_id());
    req.set_login_session_id(nickanme_login_ssid);


    stub.GetUserInfo(&cntl, &req, &rsp, nullptr);
    ASSERT_FALSE(cntl.Failed());
    ASSERT_TRUE(rsp.success());
    ASSERT_EQ(user_info.user_id(), rsp.user_info().user_id());
    ASSERT_EQ(user_info.nickname(), rsp.user_info().nickname());
    ASSERT_EQ(user_info.description(), rsp.user_info().description());
    ASSERT_EQ("", rsp.user_info().phone());
    ASSERT_EQ(user_info.avatar(), rsp.user_info().avatar());
    
}

//设置用户头像的接口
void set_user_avatar(const std::string &uid, const std::string &avatar) 
{
    auto channel = service_manager->choose(FLAGS_user_service);//获取通信信道
    ASSERT_TRUE(channel);
    ChatSystem::SetUserAvatarReq req;
    req.set_request_id(ChatSystem::Util::uuid());
    req.set_user_id(uid);
    req.set_login_session_id(nickanme_login_ssid);
    req.set_avatar(avatar);
    ChatSystem::SetUserAvatarRsp rsp;
    brpc::Controller cntl;
    ChatSystem::UserService_Stub stub(channel.get());
    stub.SetUserAvatar(&cntl, &req, &rsp, nullptr);
    ASSERT_FALSE(cntl.Failed());
    ASSERT_TRUE(rsp.success());
}

TEST(用户子服务测试, 批量用户信息获取测试) 
{
    set_user_avatar("uid1", "uid1的头像数据");
    set_user_avatar("uid2", "uid2的头像数据");

    auto channel = service_manager->choose(FLAGS_user_service);
    ASSERT_TRUE(channel);
    //发起User Rpc调用
    // 2.实例化pb中的UserService_Stub类对象；
    ChatSystem::UserService_Stub stub(channel.get());
    // 3.发起rpc请求，获取响应进行处理；
    brpc::Controller cntl;
    ChatSystem::GetMultiUserInfoReq req;
    ChatSystem::GetMultiUserInfoRsp rsp;

    req.set_request_id(ChatSystem::Util::uuid());
    req.add_users_id("uid1");
    req.add_users_id("uid2");
    req.add_users_id("2776-109f8f05-0000");
    req.add_users_id("fbf1-610d0c16-0000");


    stub.GetMultiUserInfo(&cntl, &req, &rsp, nullptr);
    ASSERT_FALSE(cntl.Failed());
    ASSERT_TRUE(rsp.success());
    auto users_map = rsp.users_info();
    ASSERT_EQ(users_map["uid1"].user_id(), "uid1");
    ASSERT_EQ(users_map["uid1"].nickname(), "nickname1");
    ASSERT_EQ(users_map["uid1"].description(), "哥只是个传说");
    ASSERT_EQ(users_map["uid1"].phone(), "15566667777");
    ASSERT_EQ(users_map["uid1"].avatar(), "uid1的头像数据");

    ASSERT_EQ(users_map["uid2"].user_id(), "uid2");
    ASSERT_EQ(users_map["uid2"].nickname(), "nickname2");
    ASSERT_EQ(users_map["uid2"].description(), "写代码的神");
    ASSERT_EQ(users_map["uid2"].phone(), "15577778888");
    ASSERT_EQ(users_map["uid2"].avatar(), "uid2的头像数据");

    ASSERT_EQ(users_map["2776-109f8f05-0000"].user_id(), "2776-109f8f05-0000");
    ASSERT_EQ(users_map["2776-109f8f05-0000"].nickname(), "测试昵称3");
    ASSERT_EQ(users_map["2776-109f8f05-0000"].description(), "这是一条测试签名2");
    ASSERT_EQ(users_map["2776-109f8f05-0000"].phone(), "");
    ASSERT_EQ(users_map["2776-109f8f05-0000"].avatar(), "nickname3的头像数据");

    ASSERT_EQ(users_map["fbf1-610d0c16-0000"].user_id(), "fbf1-610d0c16-0000");
    ASSERT_EQ(users_map["fbf1-610d0c16-0000"].nickname(), "测试昵称1");
    ASSERT_EQ(users_map["fbf1-610d0c16-0000"].description(), "这是一条测试签名");
    ASSERT_EQ(users_map["fbf1-610d0c16-0000"].phone(), "");
    ASSERT_EQ(users_map["fbf1-610d0c16-0000"].avatar(), "");

}

std::string getcode(const std::string& phone)
{
    auto channel = service_manager->choose(FLAGS_user_service);
    if(!channel)
    {
        return std::string();
    } 

    //发起User Rpc调用
    // 2.实例化pb中的UserService_Stub类对象；
    ChatSystem::UserService_Stub stub(channel.get());
    // 3.发起rpc请求，获取响应进行处理；
    brpc::Controller cntl;
    ChatSystem::PhoneVerifyCodeReq req;
    ChatSystem::PhoneVerifyCodeRsp rsp;
    req.set_request_id(ChatSystem::Util::uuid());
    req.set_phone_number(phone);

    stub.GetPhoneVerifyCode(&cntl, &req, &rsp, nullptr);
    if(cntl.Failed() == true)
    {
        LOG_ERROR("Rpc 调用失败: {}", cntl.ErrorText());
        return std::string();
    }
    if(rsp.success() == false)
    {
        LOG_ERROR("响应出错：{}", rsp.errmsg());
        return std::string();
    }
    return rsp.verify_code_id();
}

TEST(用户子服务测试, 手机号注册测试) 
{
    std::string verify_code_id = getcode("15511223344");
    auto channel = service_manager->choose(FLAGS_user_service);
    ASSERT_TRUE(channel);

    //发起User Rpc调用
    // 2.实例化pb中的UserService_Stub类对象；
    ChatSystem::UserService_Stub stub(channel.get());
    // 3.发起rpc请求，获取响应进行处理；
    brpc::Controller cntl;
    ChatSystem::PhoneRegisterReq req;
    ChatSystem::PhoneRegisterRsp rsp;

    req.set_request_id(ChatSystem::Util::uuid());
    req.set_phone_number("15511223344");
    req.set_verify_code("1024");
    req.set_verify_code_id(verify_code_id);

    stub.PhoneRegister(&cntl, &req, &rsp, nullptr);
    ASSERT_FALSE(cntl.Failed());
    ASSERT_TRUE(rsp.success());
    
}

TEST(用户子服务测试, 手机号登录测试) 
{
    std::string verify_code_id = getcode("15511223344");
    auto channel = service_manager->choose(FLAGS_user_service);
    ASSERT_TRUE(channel);

    //发起User Rpc调用
    // 2.实例化pb中的UserService_Stub类对象；
    ChatSystem::UserService_Stub stub(channel.get());
    // 3.发起rpc请求，获取响应进行处理；
    brpc::Controller cntl;
    ChatSystem::PhoneLoginReq req;
    ChatSystem::PhoneLoginRsp rsp;

    req.set_request_id(ChatSystem::Util::uuid());
    req.set_phone_number("15511223344");
    req.set_verify_code("1024");
    req.set_verify_code_id(verify_code_id);


    stub.PhoneLogin(&cntl, &req, &rsp, nullptr);
    ASSERT_FALSE(cntl.Failed());
    ASSERT_TRUE(rsp.success());
    phone_login_ssid = rsp.login_session_id();
}

TEST(用户子服务测试, 用户修改手机号测试) 
{
    std::string verify_code_id = getcode("15599998888");
    auto channel = service_manager->choose(FLAGS_user_service);
    ASSERT_TRUE(channel);

    //发起User Rpc调用
    // 2.实例化pb中的UserService_Stub类对象；
    ChatSystem::UserService_Stub stub(channel.get());
    // 3.发起rpc请求，获取响应进行处理；
    brpc::Controller cntl;
    ChatSystem::SetUserPhoneNumberReq req;
    ChatSystem::SetUserPhoneNumberRsp rsp;

    req.set_request_id(ChatSystem::Util::uuid());
    std::string user_id;
    std::cout << "修改手机号时, 输入用户ID: ";
    std::cin >> user_id;
    req.set_user_id(user_id);
    req.set_login_session_id(phone_login_ssid);
    req.set_phone_number("15599998888");
    req.set_verify_code("1024");
    req.set_verify_code_id(verify_code_id);


    stub.SetUserPhoneNumber(&cntl, &req, &rsp, nullptr);
    ASSERT_FALSE(cntl.Failed());
    ASSERT_TRUE(rsp.success()); 
}

int main(int argc, char* argv[])
{
    testing::InitGoogleTest(&argc, argv);
    google::ParseCommandLineFlags(&argc, &argv, true);
    ChatSystem::InitLogger(FLAGS_run_mode, FLAGS_log_file, FLAGS_log_level);

    //1. 先去注册中心进行服务的发现---发现user_server的服务器节点地址信息并实例化通信信道
    //1.1 先构造Rpc整体的服务管理信道类
    service_manager = std::make_shared<ChatSystem::ServiceManager>();
    service_manager->declared(FLAGS_user_service);  //设置需要关心的服务
    auto put_cb = std::bind(&ChatSystem::ServiceManager::onServiceOnline, service_manager.get(), std::placeholders::_1, std::placeholders::_2);
    auto del_cb = std::bind(&ChatSystem::ServiceManager::onServiceOffline, service_manager.get(), std::placeholders::_1, std::placeholders::_2);
    //1.2 构造服务发现对象 
    ChatSystem::Discovery::ptr dclient = std::make_shared<ChatSystem::Discovery>(FLAGS_etcd_host, FLAGS_base_service, put_cb, del_cb);
    
    user_info.set_nickname("测试昵称3");
    user_info.set_user_id("2776-109f8f05-0000");
    user_info.set_description("这是一条测试签名2");
    user_info.set_phone("15544445555");
    user_info.set_avatar("nickname3的头像数据");

    //开始所有的单元测试
    return RUN_ALL_TESTS();
}
